#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include "InetAddr.hpp"
#include "log.hpp"
#include <errno.h>
#include <pthread.h>
#include "ThreadPool.hpp"
#include <functional>
using namespace LogModule;

using func_t = std::function<std::string(std::string cmd, InetAddr &cli)>;
class server
{
public:
    server(uint16_t port,func_t func)
        : _listenfd(-1), _port(port),_func(func)
    {
    }
    ~server()
    {
    }
    void MY_server(int sockfd, InetAddr &cli)
    {
        while (1)
        {
            char buffer[1024];
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n < 0)
            {
                std::cout << "read fail!" << std::endl;
                close(sockfd);
                break;
            }
            else if (n > 0)
            {
                buffer[n] = '\0';

                std::string messager=_func(std::string(buffer),cli);
              /*   std::cout << cli.Ip() << "-" << cli.Port() << "say:" << buffer << std::endl;
                std::string messager = "server echo# ";
                messager += buffer; */
                write(sockfd, messager.c_str(), messager.size());
            }
            else
            {
                std::cout << cli.Ip() << "-" << cli.Port() << "exit " << std::endl;
                close(sockfd);
                break;
            }
        }
    }
    void Init()
    {
        int ret = socket(AF_INET, SOCK_STREAM, 0);
        if (ret == -1)
        {
            LOG(LogLevel::ERROR) << "socket fail!";
            perror("socket:");
            exit(1);
        }
        LOG(LogLevel::INFO) << "socket success!!";
        _listenfd = ret;
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        socklen_t len = sizeof(local);
        int n = bind(_listenfd, (struct sockaddr *)&local, len);
        if (n == 0)
        {
            LOG(LogLevel::INFO) << "bind success!!";
        }
        else
        {
            std::cout << n << std::endl;
            LOG(LogLevel::FATAL) << "bind fail!!";
            perror("bind");
            exit(2);
        }

        int s = listen(_listenfd, 5);
        if (s < 0)
        {
            LOG(LogLevel::INFO) << "listen success!!";
        }
    }
    class ThreadData
    {
    public:
        ThreadData(int sockfd, InetAddr &cli, server *serve)
            : _id(-1), _sockfd(sockfd), _serve(serve), _cli(cli)
        {
        }
        ~ThreadData()
        {
        }
        pthread_t _id;
        int _sockfd;
        server *_serve;
        InetAddr _cli;
    };
    static void *Routine(void *args)
    {
        std::cout << "Routine" << std::endl;
        ThreadData *td = static_cast<ThreadData *>(args);
        pthread_detach(td->_id);
        td->_serve->MY_server(td->_sockfd, td->_cli);
        delete td;
        return nullptr;
    }
    void Start()
    {
        while (1)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, (struct sockaddr *)&peer, &len);
            InetAddr local(peer);
            std::cout << "接收到一个客户端！" << std::endl;
            // version 2 :<多线程版本>
            ThreadData *td = new ThreadData(sockfd, local, this);
            int ret = pthread_create(&td->_id, nullptr, Routine, td);
            if (ret != 0)
            {
                perror("create");
            }

            // version:1 <多进程版本>
            //  向客户端提供服务
            /*  pid_t id = fork();
             if (id == 0)
             {
                 close(_listenfd);
                 pid_t id = fork();
                 if (id == 0)
                 {
                     // 孙子进程执行任务后退出由1号进程领养
                     MY_server(sockfd);
                     exit(0);
                 }
                 else
                 {
                     exit(0);
                 }
             }
             else if(id<0)
             {
                 LOG(LogLevel::FATAL)<<"fork fail!!!";
                 exit(3);
             }
             else
             {
                 close(sockfd);
                 pid_t n=waitpid(id,nullptr,0);
                 (void)n;
             } */

            /* //version 3:<线程池版本>
             ThreadPool<task_t>::GetInstance()->Enqueue([this,sockfd,&local](){
                 return this->MY_server(sockfd,local);
             }); */
        }
    }

private:
    int _listenfd;
    uint16_t _port;
    func_t _func;
};